#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/prctl.h>

#include "auth.h"
#include "driver.h"
#include "ipc.h"
#include "fingerdb.h"

/********************************
*                               *
*      This file contents       *
*   server-side IPC functions   *
*                               *
********************************/



/***************************
*          UTILS           *
***************************/

/**********************************************************************
func waitSemaphoreWhileSocket
	wait semaphore and monitor socket at same time
input
	sem - semaphore which need wait
	soc - socket which need monitor
return
	0 if semaphore has been got
	-ECONNRESET on socket drop
	negative on error
***********************************************************************/
static int waitSemaphoreWhileSocket( sem_t* sem, int soc ){
	
	struct timespec t;
	
	while( !write(soc, NULL, 0) ) {
		
		if( clock_gettime(CLOCK_REALTIME, &t) ){
			perror( "[ipcd] clock" );
			return -EINVAL;//clock error
		}
		t.tv_sec += 2;
		
		if( !sem_timedwait(sem, &t) ) return 0;//sem got
		else if( errno != ETIMEDOUT ){
			perror( "[ipcd] sem" );
			return -EINTR;//semaphore error
		}
	}
	
	perror( "[ipcd] sock" );
	return -ECONNRESET;//socket drop
}

static void driverSwitchMode( struct driverInstance* this, unsigned char mode ){
	
	if( this->modeIndicator == mode ) return;
	
	//switch mode
	this->modeSwitcher = mode;
	
	if( this->modeIndicator == MODE_IDLE ) sem_post( &this->semaphoreIdle );
	else if( this->modeIndicator == MODE_SCANNING && this->driverState == STATE_WAIT_IPC ){
		sem_post( &this->semaphoreScan );
		goto l_wait_enter;
	} 
	
	//wait exit mode notification
	sem_wait( &this->semaphoreIpc );
	
l_wait_enter: //wait enter mode notification
	sem_wait( &this->semaphoreIpc );
}

/************************************************
func getFingerImageFromScanner
	scan finger and get fingerprint
	caller must switch mode after this
proto:
	if driver send message to ipcd, ipcd send message to socket
	<IPC_DRIVER_MESSAGE> <message (unsigned char)>
return
	0 on success
	-ECONNRESET on socket drop or error
	any negative codes from fingerScanPolling
*************************************************/
static int getFingerImageFromScanner( struct driverInstance* this, int socket ){
	
	unsigned char driverMessage;
	
	if( this->modeIndicator != MODE_SCANNING ) driverSwitchMode( this, MODE_SCANNING );
	if( this->driverState == STATE_WAIT_IPC ) sem_post( &this->semaphoreScan );
	
	//prompt the user to swipe the scanner
	if( write(socket, &IPC_DRIVER_MESSAGE,       1) != 1 ) goto l_abort;
	if( write(socket, &IPC_PROMPT_SWIPE_SCANNER, 1) != 1 ) goto l_abort;
	
l_waitSemaphore:
	//wait semaphore and monitor socket
	if( waitSemaphoreWhileSocket(&this->semaphoreIpc, socket) ) goto l_abort;
	
	if( this->scanResult > 0 ){//message from driver
		driverMessage = this->scanResult;
		if( write(socket, &IPC_DRIVER_MESSAGE, 1) != 1 ) goto l_abort;
		if( write(socket, &driverMessage,      1) != 1 ) goto l_abort;
		sem_post( &this->semaphoreScan );
		goto l_waitSemaphore;
	}
	
	//scan done or error
	return this->scanResult;
	
l_abort: //tell driver abort
	this->modeSwitcher = MODE_IDLE;
	sem_wait( &this->semaphoreIpc );
	if( this->scanResult > 0 ){
		sem_post( &this->semaphoreScan );
		goto l_abort;
	}
	this->modeSwitcher = MODE_SCANNING;
	return -ECONNRESET;
}

/*
send to socket:
	<length> [content]
return
	ret =  0 - ok
	ret = -1 - wrong field type
	ret = -2 - db error
	ret = -3 - socket error
*/
static int printFieldContentToSocket( int socket, int recordId, const struct ipc_field* field ){
	
	int value;
	int len;
	char buf[1024];
	
	//read data from db into buffer
	if( field->type == 'i' ){
		//read data as integer and convert to text
		len = fingerdbGetField( recordId, field->name, &value, sizeof(value) );
		if( len < 0 ) return -2;
		if( len > 0 ){
			sprintf( buf, "%i", value );
			len = strlen( buf );
		}
	}else if( field->type == 't' ){
		//read data as regular text
		len = fingerdbGetField( recordId, field->name, buf, 1024 );
		if( len < 0 ) return -2;
		buf[len] = 0x00;//make sure string is null-terminated
	}else return -1;
	
	//send data to socket
	if( write(socket, &len, sizeof(len)) != sizeof(len) ) goto l_perror;
	if( len > 0 ){
		if( write(socket, buf, len) != len ) goto l_perror;
	}
	
	return 0;
	
l_perror:
	perror( "[ipcd]" );
	return -3;
}

/***************************
*       OPERATIONS         *
***************************/
/*
request: <IPC_TOUCHPAD> <mode>
response: <mode> || <IPC_ERROR>
*/
static void touchpadControl( struct driverInstance* this, int socket ){
	
	unsigned char cmd;
	unsigned char ans;
	
	if( recv( socket, &cmd, 1, MSG_WAITALL) != 1 ) goto l_perror;
	
	
	if( cmd == IPC_TOUCHPAD_OFF ) driverSwitchMode( this, MODE_IDLE );
	else if( cmd != IPC_TOUCHPAD_STATUS ){
		
		if( this->modeIndicator != MODE_TOUCHPAD ){
			if(      cmd == IPC_TOUCHPAD_MOUSE  ) this->touchpadMode = MODE_TOUCHPAD_MOUSE;
			else if( cmd == IPC_TOUCHPAD_WHEELS ) this->touchpadMode = MODE_TOUCHPAD_WHEELS;
			else if( cmd == IPC_TOUCHPAD_ARROWS ) this->touchpadMode = MODE_TOUCHPAD_ARROWS;
			else{
				ans = IPC_ERROR;
				goto l_ans;
			}
			
			driverSwitchMode( this, MODE_TOUCHPAD );
		} else {
			if(      cmd == IPC_TOUCHPAD_MOUSE  ) this->modeSwitcher = MODE_TOUCHPAD_MOUSE;
			else if( cmd == IPC_TOUCHPAD_WHEELS ) this->modeSwitcher = MODE_TOUCHPAD_WHEELS;
			else if( cmd == IPC_TOUCHPAD_ARROWS ) this->modeSwitcher = MODE_TOUCHPAD_ARROWS;
			else{
				ans = IPC_ERROR;
				goto l_ans;
			}
			
			sem_wait( &this->semaphoreIpc );
			
		}
	}
	
	if( this->modeIndicator != MODE_TOUCHPAD ) ans = IPC_TOUCHPAD_OFF;
	else{
		if(      this->touchpadMode == MODE_TOUCHPAD_MOUSE  ) ans = IPC_TOUCHPAD_MOUSE;
		else if( this->touchpadMode == MODE_TOUCHPAD_WHEELS ) ans = IPC_TOUCHPAD_WHEELS;
		else if( this->touchpadMode == MODE_TOUCHPAD_ARROWS ) ans = IPC_TOUCHPAD_ARROWS;
		else ans = IPC_ERROR;
	}
	
l_ans:
	if( write(socket, &ans, 1) != 1 ) goto l_perror;
	
	return;
	
l_perror:
	perror( "[ipcd]" );
}

/*
request:  <IPC_USER_AUTH> <mode> <userlen(int)> <username>
response: <IPC_SUCCESS> || <IPC_ERROR> || <IPC_DRIVER_MESSAGE> <MSG>
          also messages from driver
*/
static void authUser( struct driverInstance* this, int socket ){
	
	int res;
	char username[40];
	int usernameLength;
	unsigned char savedMode;
	unsigned char foundFlag;
	unsigned char authMode;
	
	foundFlag = 0x00;
	savedMode = this->modeIndicator;
	
	//read auth mode
	if( recv(socket, &authMode, 1, MSG_WAITALL) != 1 ) goto l_perror;
	
	//username length receive and check
	if( recv(socket, &usernameLength, sizeof(usernameLength), MSG_WAITALL) != sizeof(usernameLength) ) goto l_perror;
	if( usernameLength < 1 || usernameLength > 32 ) goto l_sendResult;
	
	//username receive
	if( recv(socket, username, usernameLength, MSG_WAITALL) != usernameLength ) goto l_perror;
	username[usernameLength] = 0x00; //make sure string null-terminated
	
	if( authMode == IPC_USER_AUTH_ACTIVE ){//auth in active mode
		
		//scan finger
		res = getFingerImageFromScanner( this, socket );
		if( res == -ECONNRESET ) goto l_exit;
		if( res ) goto l_sendResult;
		
		//search match in finger db
		res = authSearchMatch( this->data, username );
		if( res > 0 ) foundFlag = 0xff;
		
	}else if( authMode == IPC_USER_AUTH_PASSIVE ){//auth in passive mode
		
		//check current state
		if( this->passiveAuthModeIndicator != PA_STOP ){
			printf( "[ipcd] ERROR: Unexpected passive auth state.\n" );
			goto l_sendResult;
		}
		
		//setup passive auth mode
		this->passiveAuthModeSwitcher = PA_START;
		
		//switch to idle
		driverSwitchMode( this, MODE_IDLE );
		
		//notise idle mode about passive auth start and wait response
		sem_post( &this->semaphoreIdle );
		sem_wait( &this->semaphoreIpc );
		
		//check response
		if( this->passiveAuthModeIndicator != PA_START ){
			printf( "[ipcd] FATAL ERROR: Passive auth start return unexpected response 0x%02x\n", this->passiveAuthModeIndicator );
			goto l_sendResult;
		}
		
		//set username for auth and signal to main thread for continue
		this->passiveAuthUsername = username;
		sem_post( &this->semaphoreScan );
		
		//prompt the user to swipe the scanner
		if( write(socket, &IPC_DRIVER_MESSAGE,       1) != 1 ) goto l_abort;
		if( write(socket, &IPC_PROMPT_SWIPE_SCANNER, 1) != 1 ) goto l_abort;
		
		//wait semaphore and monitor socket
		res = waitSemaphoreWhileSocket( &this->semaphoreIpc, socket );
		if( !res ){//semaphore got
			
			//check response
			if(      this->passiveAuthModeIndicator == PA_SUCCESS ) foundFlag = 0xff;
			else if( this->passiveAuthModeIndicator != PA_FAILED ){
				printf( "[ipcd] FATAL ERROR: Passive auth return unexpected response: 0x%02x\n", this->passiveAuthModeIndicator );
				goto l_sendResult;
			}
			
			//disabling passive auth
			this->passiveAuthUsername      = NULL;
			this->passiveAuthModeSwitcher  = PA_STOP;
			this->passiveAuthModeIndicator = PA_STOP;
			sem_post( &this->semaphoreScan );
			
		} else {//socket drop or any error
			
l_abort:
			//signal to idle mode to stop passive auth 
			this->passiveAuthModeSwitcher = PA_STOP;
			sem_post( &this->semaphoreIdle );
			
			//wait for the stop response
l_waitStopResponse:
			sem_wait( &this->semaphoreIpc );
			
			//if it is response with auth result
			if( this->passiveAuthModeIndicator != PA_STOP ){
				sem_post( &this->semaphoreScan );
				goto l_waitStopResponse;
			}
			
			//set username to NULL for disable passive auth
			this->passiveAuthUsername = NULL;
			sem_post( &this->semaphoreScan );
		}
	}
	
l_sendResult:
	//send result
	if( write(socket, foundFlag ? &IPC_SUCCESS : &IPC_ERROR, 1) != 1 ) goto l_perror;
	goto l_exit;
	
l_perror:
	perror( "[ipcd]" );
	
l_exit:
	//restore previous mode
	driverSwitchMode( this, savedMode );
}

/*
proto:
	<cmd>
	<id> <userlen> [user] <descriptionlen> [description]
	...
	<0>
*/
static void listFinger( int socket ){
	
	void* db;
	int id;
	int i;
	
	db = fingerdbOpen();
	if( !db ) return;
	
	//cmd
	if( write(socket, &IPC_FINGER_LIST, 1) != 1 ) goto l_perror;
	
l_searchNext:
	id = fingerdbSearchNextId( db );
	if( !id ){
		//end of list
		id = 0;
		if( write(socket, &id, sizeof(id)) != sizeof(id) ) goto l_perror;
		goto l_closedb;
	}
	
	//send id
	if( write(socket, &id, sizeof(id)) != sizeof(id) ) goto l_perror;
	
	//send fields
	for( i = 0; i < 2; i++ ){
		if( printFieldContentToSocket(socket, id, &ipcFieldList[i]) ) goto l_closedb;
	}
	
	goto l_searchNext;
	
l_perror:
	perror( "[ipcd]" );
	
l_closedb:
	fingerdbClose( db );
}

/*
request: IPC_FINGER_DETECT
answer:  IPC_FINGER_DETECT <id(int)> || IPC_ERROR
         also messages from driver
*/
static void fingerDetect( struct driverInstance* this, int socket ){
	
	int res;
	unsigned char savedMode;
	
	savedMode = this->modeIndicator;
	
	//finger scan
	res = getFingerImageFromScanner( this, socket );
	if( res == -ECONNRESET ) goto l_exit;
	
	//search matches
	if( !res ) res = authSearchMatch( this->data, NULL );
	
	//send result
	if( res < 0 ){
		if( write(socket, &IPC_ERROR,         1          ) != 1           ) goto l_perror;
	} else {
		if( write(socket, &IPC_FINGER_DETECT, 1          ) != 1           ) goto l_perror;
		if( write(socket, &res,               sizeof(res)) != sizeof(res) ) goto l_perror;
	}
	
	goto l_exit;
	
l_perror:
	perror( "[ipcd]" );
	
l_exit:
	driverSwitchMode( this, savedMode );
}

/********************
*       ADMIN       *
********************/

/*
request: <IPC_FINGER_ADD> <MODE>
answer
	<IPC_FINGER_ADD> <int>
	<IPC_SUCCESS> <ID>
	<IPC_ERROR>
	also messages from driver
*/
static void newFinger( struct driverInstance* this, int socket ){
	
	int res;
	unsigned char addMode;
	unsigned char savedMode;
	
	int attempts;
	
	int* currentXytCount;
	struct xyt_packed* currentXyt;
	int xyt1Count;
	int xyt2Count;
	struct xyt_packed xyt1[NBIS_XYT_MAX_COUNT];
	struct xyt_packed xyt2[NBIS_XYT_MAX_COUNT];
	
	savedMode = this->modeIndicator;
	
	//read mode
	if( recv(socket, &addMode, 1, MSG_WAITALL) != 1 ){
		perror( "[ipcd]" );
		return;
	}
	
	//check socket security
	if( checkSocketSecurity(socket) ){
		if( write(socket, &IPC_DENIED, 1) != 1 ) perror( "[ipcd]" );
		return;
	}
	
	//check mode
	if( addMode != IPC_FINGER_ADD_SINGLE && addMode != IPC_FINGER_ADD_BEST ){
		printf( "[ipcd] Unknown new finger add mode: 0x%02x\n", addMode );
		if( write(socket, &IPC_ERROR, 1) != 1 ) perror( "[ipcd]" );
		return;
	}
	
	//init some vars
	xyt1Count = 0;
	xyt2Count = 0;
	attempts = 0;
	currentXyt = xyt1;
	currentXytCount = &xyt1Count;
	
l_scanAgain:
	//scan finger
	res = getFingerImageFromScanner( this, socket );
	if( res == -ECONNRESET ) goto l_exit;
	if( res ) goto l_sendError;
	
	//get minutiae on fingerprint
	*currentXytCount = nbisPgmToMinutiae( this->data, currentXyt );
	if( *currentXytCount < 0 ) goto l_sendError;
	
	//notify client about scan result
	if( write(socket, &IPC_FINGER_ADD, 1                       ) != 1                        ) goto l_perror;
	if( write(socket, currentXytCount, sizeof(*currentXytCount)) != sizeof(*currentXytCount) ) goto l_perror;
	
	if( addMode == IPC_FINGER_ADD_SINGLE ) goto l_register;
	
	//switch to minimal
	if( currentXyt == xyt1 ){
		if( xyt1Count > xyt2Count ){
			attempts = 0;
			currentXyt = xyt2;
			currentXytCount = &xyt2Count;
		}
	}else{
		if( xyt2Count > xyt1Count ){
			attempts = 0;
			currentXyt = xyt1;
			currentXytCount = &xyt1Count;
		}
	}
	
	//check attempts count
	if( attempts < 3 ){
		attempts++;
		goto l_scanAgain;
	}
	
	//select best fingerprint
	if( currentXyt == xyt1 ){
		currentXyt = xyt2;
		currentXytCount = &xyt2Count;
	}else{
		currentXyt = xyt1;
		currentXytCount = &xyt1Count;
	}
	
l_register:
	//create new record in finger DB
	res = authEnroll( currentXyt, *currentXytCount );
	
	//send result
	if( res < 0 ){
l_sendError:
		if( write(socket, &IPC_ERROR,   1          ) != 1           ) goto l_perror;
	} else {
		if( write(socket, &IPC_SUCCESS, 1          ) != 1           ) goto l_perror;
		if( write(socket, &res,         sizeof(res)) != sizeof(res) ) goto l_perror;
	}
	
	goto l_exit;
	
l_perror:
	perror( "[ipcd]" );
	
l_exit:
	driverSwitchMode( this, savedMode );
}

/*
proto
	<IPC_SUCCESS> or <IPC_ERROR>
	
	<len> [data] user
	<len> [data] desc
	<len> [data] threshold
	<len> [data] action

*/
static void viewFinger( int socket ){
	
	int i;
	int id;
	
	//read id
	if( recv(socket, &id, sizeof(id), MSG_WAITALL) != sizeof(id) ) goto l_perror;
	
	//check socket security
	if( checkSocketSecurity(socket) ){
		if( write(socket, &IPC_DENIED, 1) != 1 ) goto l_perror;
		return;
	}
	
	//check id exist
	if( !fingerdbCheckIdExist(id) ){
		if( write(socket, &IPC_ERROR, 1) != 1 ) goto l_perror;
		return;
	}
	
	if( write(socket, &IPC_SUCCESS, 1) != 1 ) goto l_perror;
	
	//read content in fields and send it
	for( i = 0; i < 4; i++ ){
		if( printFieldContentToSocket(socket, id, &ipcFieldList[i]) ) return;
	}
	
	return;
l_perror:
	perror( "[icd]" );
}

/*
request: <IPC_FINGER_EDIT> <ID> <FIELD ID> <LENGTH> [NEW VALUE]
answer: <IPC_SUCCESS> || <IPC_ERROR>
*/
static void editFinger( int socket ){
	
	int i;
	int res;
	int id;
	unsigned char fieldId;
	int len;
	char buf[1024];
	int value;
	const struct ipc_field* field = NULL;
	
	//receive id, fieldid, len and new value
	if( recv(socket, &id,      sizeof(id),  MSG_WAITALL) != sizeof(id)  ) goto l_perror;
	if( recv(socket, &fieldId, 1,           MSG_WAITALL) != 1           ) goto l_perror;
	if( recv(socket, &len,     sizeof(len), MSG_WAITALL) != sizeof(len) ) goto l_perror;
	if( len > 1023 || len < 0 ){//check len
		res = -1;
		goto l_sendAnswer;
	}
	
	if( len ){
		if( recv(socket, buf, len, MSG_WAITALL) != len ) goto l_perror;
	}
	buf[len] = 0x00; //string must be null-terminated
	
	//check socket security
	if( checkSocketSecurity(socket) ){
		if( write(socket, &IPC_DENIED, 1) != 1 ) goto l_perror;
		return;
	}
	
	//check requested field
	for( i = 0; ipcFieldList[i].name; i++ ) if( ipcFieldList[i].id == fieldId ){
		field = &ipcFieldList[i];
		goto l_found;
	}
	
	printf( "%s) WARNING! Wrong field requested: 0x%02x\n", __FUNCTION__, fieldId );
	res = -1;
	goto l_sendAnswer;
	
l_found:
	//convert text to int if need
	if( field->type == 'i' ){
		
		//if len == 0, then clear field
		if( !len ) goto l_setAsText;
		
		if( sscanf(buf, "%i", &value) != 1 ){
			res = -1;
			goto l_sendAnswer;
		}
		//set value as int
		res = fingerdbSetField( id, field->name, &value, sizeof(value) );
	}else if( field->type == 't' ){
l_setAsText: //set new value as text
		res = fingerdbSetField( id, field->name, buf, len );
	} else {
		printf( "%s) WARNING: unknow field type: %c\n", __FUNCTION__, field->type );
		res = -1;
	}
	
l_sendAnswer: //send answer
	if( write(socket, res ? &IPC_ERROR : &IPC_SUCCESS, 1) != 1 ) goto l_perror;
	
	return;
	
l_perror:
	perror( "[ipcd]" );
}

/*
request   <IPC_FINGER_TEST> <id>
response: <IPC_FINGER_TEST> <score> || <IPC_ERROR>
          also messages from driver
*/
static void testFinger( struct driverInstance* this, int socket ){
	
	int id;
	int res;
	unsigned char savedMode;
	
	savedMode = this->modeIndicator;
	
	//read id
	if( recv(socket, &id, sizeof(id), MSG_WAITALL) != sizeof(id) ) goto l_perror;
	
	//check socket security
	if( checkSocketSecurity(socket) ){
		if( write(socket, &IPC_DENIED, 1) != 1 ) perror( "[ipcd]" );
		return;
	}
	
	//check id exist
	if( !fingerdbCheckIdExist(id) ){
		if( write(socket, &id, sizeof(id)) != sizeof(id) ) goto l_perror;
		return;
	}
	
	//scan finger and calculate match score
	res = getFingerImageFromScanner( this, socket );
	if( !res ) res = authTest( id, this->data );
	
	//send result
	if( res < 0 ){
		if( write(socket, &IPC_ERROR, 1) != 1 ) perror( "[ipcd]" );
	} else {
		if( write(socket, &IPC_FINGER_TEST, 1) != 1 ) perror( "[ipcd]" );
		else if( write(socket, &res, sizeof(res)) != sizeof(res) ) perror( "[ipcd]" );
	}
	
	driverSwitchMode( this, savedMode );
	
	return;
	
l_perror:
	perror( "[ipcd]" );
}

/*
request: <IPC_FINGER_REMOVE> <ID>
answer:  <IPC_SUCCESS> or <IPC_FAILED>
*/
static void removeFinger( int socket ){
	
	int id;
	
	//read id
	if( recv(socket, &id, sizeof(id), MSG_WAITALL) != sizeof(id) ) goto l_perror;
	
	//check socket security
	if( checkSocketSecurity(socket) ){
		if( write(socket, &IPC_DENIED, 1) != 1 ) perror( "[ipcd]" );
		return;
	}
	
	//remove record from DB ande send result
	if( !fingerdbRemoveFinger(id) ){
		if( write(socket, &IPC_SUCCESS, 1) != 1 ) goto l_perror;
	}else {
		if( write(socket, &IPC_ERROR, 1) != 1 ) goto l_perror;
	}
	
	return;
	
l_perror:
	perror( "[ipcd]" );
}


/***************************
*     HANDLER SWITCHER     *
***************************/
static void connectionHandler( struct driverInstance* this, int socket ){
	
	unsigned char cmd;
	
l_recvCmd:
	//read command from socket
	if ( recv(socket, &cmd, 1, MSG_WAITALL) != 1 ) return;
	
	//user cmd
	if(      cmd == IPC_TOUCHPAD      ) touchpadControl( this, socket );
	else if( cmd == IPC_USER_AUTH     ) authUser( this, socket );
	else if( cmd == IPC_FINGER_LIST   ) listFinger( socket );
	else if( cmd == IPC_FINGER_DETECT ) fingerDetect( this, socket );
	//admin cmd
	else if( cmd == IPC_FINGER_ADD    ) newFinger( this, socket );
	else if( cmd == IPC_FINGER_VIEW   ) viewFinger( socket );
	else if( cmd == IPC_FINGER_EDIT   ) editFinger( socket );
	else if( cmd == IPC_FINGER_TEST   ) testFinger( this, socket );
	else if( cmd == IPC_FINGER_REMOVE ) removeFinger( socket );
	else{
		printf( "[ipcd] Received unknown ipc command: 0x%02x\n", cmd );
		if( write(socket, &IPC_ERROR, 1) != 1 ){//unknown command
			perror( "[ipcd] (unk cmd)" ); 
			return;
		}
	}
	
	goto l_recvCmd;
}

/*************************
*    IPCD ENTRY POINT    *
*************************/
void* ipcdEntryPoint( void* arg ){
	
	struct driverInstance* this = arg;
	
	int mySocket;
	int clientSocket;
	struct sockaddr_un socketAddress;
	
	prctl( PR_SET_NAME, "ipcd", 0, 0, 0 );
	
	//Create local socket.
	mySocket = socket( AF_UNIX, SOCK_STREAM, 0 );
	
	if( mySocket == -1 ) {
		printf( "[ipcd] Unable create socket %s\n", IPC_SOCKET );
		return NULL;
	}
	
	memset( &socketAddress, 0, sizeof(struct sockaddr_un) );
	
	// Bind socket to socket name.
	socketAddress.sun_family = AF_UNIX;
	strncpy( socketAddress.sun_path, IPC_SOCKET, sizeof(socketAddress.sun_path) - 1 );
	
	if( bind(mySocket, (const struct sockaddr*) &socketAddress, sizeof(struct sockaddr_un)) ){
		perror( "[ipcd] bind" );
		return NULL;
	}
	
	//Prepare for accepting connections.
	if( listen(mySocket, 5) ){
		perror( "[ipcd] listen" );
		return NULL;
	}
	
	//This is the main loop for handling connections.
	for(;;) {
		//Wait for incoming connection.
		clientSocket = accept( mySocket, NULL, NULL );
		if( clientSocket == -1 ) {
			perror( "[ipcd] accept" );
			break;
		}
		
		//handle command
		connectionHandler( this, clientSocket );
		
		//Close socket.
		close( clientSocket );
		
	}
	
	close( mySocket );
	
	return NULL;
}

